# -*- coding: utf-8 -*-
"""
Created on 2022/2/24

@author: Song
"""

import numpy as np
import altair as alt
import plotly.express as px
import pandas as pd
import streamlit as st
from vika import Vika

from DBTestAnalysisLib import *

vika = Vika("uskaYYRdtqFoPqcVw3KM2Kf")

st.set_page_config(page_title="行动&历史", page_icon="📈", layout="wide")

content_to_show = st.sidebar.radio(
    "表格显示内容?",
    ("最近一次测试日期", "最近一次测试耗时", "测试总数")
)

colAction, colDetail = st.columns(2)


def actionRow(device, action, db, dataset, tp_size, test, qCnt):
    r = {
        'db': db,
        'dataset': dataset,
        'tp_size': tp_size,
        'test': test,
        'b_qcnt': qCnt
    }
    try:
        if action == 'build':
            b = jenkins.build(action, {
                'dataset': r['dataset'],
                'data_size': 'T' + r['tp_size'],
                'db_name': r['db'].upper(),
                'device': device
            })
            info = ("Build " + r['db'] + '@' + r['dataset'] + r['tp_size'] + ' on ' + device)
        elif action == 'deploy':
            dbType = 'postgresql' if r['db'].lower() == 'pg' else 'neo4j'
            if 'tgl' in r['db'].lower():
                dbType = 'tcypher'
                db = r['db'].lower().replace('tgl', 'tgk')
            else:
                db = r['db'].lower()
            b = jenkins.build(action, {
                'target_host': device,
                'milestone': 'm_' + r['dataset'] + '_' + db + '_' + r['tp_size'][1:],
                'dbtype': dbType
            })
            info = ("Deploy " + r['db'] + '@' + r['dataset'] + r['tp_size'])
        elif action == 'test':
            needResult = 'true' if r['dataset'] != 'syn' else 'false'
            b = jenkins.build(action, {
                'db_host': 'data',
                'milestone': 'm_' + r['dataset'] + '_' + r['db'].lower() + '_' + r['tp_size'][1:],
                'benchmark_name': 'b_' + r['dataset'] + '_T' + r['tp_size'] + '_' + r['test'] + '_' + str(int(r['b_qcnt'])),
                'max_connection': 1,
                'need_result': needResult,
                'debug': 'false',
                'timeout': 3600,
                'timeout_p': 1800,
            })
            info = ("Test " + r['test'] + ':' + r['db'] + '@' + r['dataset'] + r['tp_size'] + ' on ' + device + (
                '(no result)' if needResult == 'false' else ''))
        elif action == 'validate':
            b = jenkins.build(action, {
                'db_host': device,
                'db_list': ','.join(r['db']),
                'dataset': r['dataset'],
                'test': r['test'],
                'tp_range': 'T' + r['tp_size'],
                'req_cnt': r[''],
                'skip_sample': 'true',
                'skip_test': 'true',
                'skip_validate': 'false',
                'max_connection': 1,
                'timeout': 1800,
                'failfast': 'false',
            })
            info = ("Validate " + ','.join(r['db']) + '@' + r['dataset'] + r['tp_size'])
        else:
            from Abstract import NotReadyErr
            raise NotReadyErr(action, 'unknown action')
    except Exception as e:
        st.error(e)
    st.snow()
    # with st.expander(info):
    #     for line in b.progressive_output():
    #         st.write(line)
    #     st.balloons()


def lcRWTest(test, db, dataset, tp_size):
    st.snow()
    query = leancloud.Query('TGraphTest')
    query.contains('TestName', test)
    query.endswith('DB', '_' + db.lower() + '_' + tp_size[1:])
    query.equal_to('Dataset', dataset.lower())
    query.equal_to('maxCon', 1)
    query.equal_to('device', 'data')
    query.add_descending('createdAt')
    query.limit(999)
    rows = query.find()

    def timeReformat(tStr):
        t0 = tStr.split(' ')
        t1 = t0[0].split('.')
        t2 = t0[1].split(':')
        month = int(t1[1])
        day = int(t1[2])
        hour = int(t2[0])
        minute = int(t2[1])
        return '{:02d}-{:02d} {:02d}:{:02d}'.format(month, day, hour, minute)

    def rowRefactor(obj):
        ti = TestNameInfo(obj.get('TestName'))
        return {
            'test': ti.test,
            'db': ti.db,
            'dataset': ti.dataset,
            'mtpSize': ti.mtpsize,
            'qtpSize': ti.qtpsize,
            'ct': timeReformat(ti.time),
            'duration': obj.get('duration'),
            'jid': obj.get('jenkinsId'),
            'device': obj.get('device'),
            'tname': ti.tn,
        }

    records = pd.DataFrame(list(map(rowRefactor, rows)))
    # st.dataframe(records, use_container_width=True)
    st.info(db + '@' + dataset + tp_size + ' ' + test)
    tmp = st.empty()
    p = tmp.progress(0)
    pp = [0]
    totalCnt = len(records)

    def alTest(row):
        p.progress(pp[0] / totalCnt)
        pp[0] += 1
        testFullName = row['tname']
        if type(testFullName) == str:
            try:
                # st.write(testFullName)
                raw = fetchLog(testFullName)
                qCnt = len(raw)
                if qCnt > 0:  # missingCnt += 1
                    raw = extractParam2Col(raw, ['id'])
                    succReq = raw.loc[raw['txSuccess'].astype('bool')]
                    succCnt = len(succReq)
                    avgT = np.mean(succReq['exeTime'])
                    l90 = succReq['exeTime'].quantile(.9)
                    std = np.std(succReq['exeTime'])
                    return [qCnt, succCnt, avgT, l90,
                            list(zip(list(succReq['id']), list(succReq['sendTime']), list(succReq['exeTime']))),
                            "{:.0f}±{:.0f}({:.0f})".format(avgT, std, succCnt)]
            except DataNotReadyErr:
                pass
        return [None, None, None, 0, [], None]

    records[['qcnt', 'succ_cnt', 'avg_t', 'l90_t', 'raw', 'content']] = records.apply(alTest, axis=1,
                                                                                      result_type="expand")
    # st.dataframe(records, use_container_width=True)
    data = records.explode('raw').reset_index()
    data[['txid', 'send_time', 'latency']] = data.apply(lambda row: row['raw'], axis=1, result_type="expand")
    data = data.sort_values('send_time', ascending=True)
    data = data.reset_index(drop=True)
    st.dataframe(data, use_container_width=True)
    # bar = alt.Chart(data).mark_bar().encode(
    #     y=alt.Y("latency:Q",
    #             # axis=alt.Axis(format="~s"),
    #             # title=None,
    #             # scale=alt.Scale(type="symlog")
    #             ),  #
    #     x=alt.X("send_time:T"),
    #     color=alt.Color("tname"),
    #     # tooltip=["db", "lct_ct", "al_l90_t", "al_succ_cnt", "al_qcnt"]
    # ).properties(
    #     width=160,
    #     height=100
    # )
    # st.altair_chart(bar)
    ffg = px.bar(data, y="latency", x=data.index, color="tname",  # pattern_shape="mtpSize", "send_time"
                 # facet_row="test",
                 # facet_col="dataset",
                 # log_y=True,
                 # text="label2show",
                 # hover_data=["db", "lct_ct", "al_l90_t", "al_succ_cnt", "al_qcnt"],
                 # color_discrete_sequence=['#ffaa6c', '#ee8683', '#c27294', '#cba451', '#0081cf', '#4e78cf', '#00a4de',
                 #                          '#00c2d0', '#00dbad', '#96ee86'],
                 )
    ffg.update_traces(width=1.0, textfont_size=12, textangle=0, textposition="outside", cliponaxis=False)
    ffg.update_layout(barmode='group', bargap=0.0, bargroupgap=0.0)
    fgg = ffg.update_yaxes(matches=None, showticklabels=True)
    st.plotly_chart(fgg)
    tmp.empty()
    st.balloons()


def showHistory(device, action, db, dataset, tp_size, test, qCnt):
    r = {
        'db': db,
        'dataset': dataset,
        'tp_size': tp_size,
        'test': test,
        'b_qcnt': qCnt
    }
    if action == 'build':
        pass
        info = ("Build " + r['db'] + '@' + r['dataset'] + r['tp_size'] + ' on ' + device)
    elif action == 'deploy':
        pass
    elif action == 'test':
        with colDetail:
            lcRWTest(r['test'], r['db'], r['dataset'], r['tp_size'])
        info = ("Test " + r['test'] + ':' + r['db'] + '@' + r['dataset'] + r['tp_size'])
    elif action == 'validate':
        b = jenkins.build(action, {
            'db_host': device,
            'db_list': ','.join(r['db']),
            'dataset': r['dataset'],
            'test': r['test'],
            'tp_range': 'T' + r['tp_size'],
            'req_cnt': r[''],
            'skip_sample': 'true',
            'skip_test': 'true',
            'skip_validate': 'false',
            'max_connection': 1,
            'timeout': 1800,
            'failfast': 'false',
        })
        info = ("Validate " + ','.join(r['db']) + '@' + r['dataset'] + r['tp_size'])
    else:
        from Abstract import NotReadyErr
        raise NotReadyErr(action, 'unknown action')

with colAction:
    device = st.radio('测试节点', ('data', 'ss', 'zh', 'master'), horizontal=True)
    action = st.radio('操作', ('build', 'deploy', 'test', 'validate'), horizontal=True)
    db = st.radio('对比系统', ('TGK', 'TGC', 'TGL', 'TGLI', 'TGKI', 'TGS', 'N1', 'N2', 'PG', 'MA'), horizontal=True)
    dataset = st.radio('数据集', ('energy', 'traffic', 'syn'), horizontal=True)
    tp_size = st.radio('时态数据量', ('.all', '.1', '.0'), horizontal=True)
    test = st.radio('测试项', ('ehistory', 'snapshot', 'aggmax', 'etpc', 'reachable', 'update', 'append'), horizontal=True)
    qCnt = st.radio('请求个数', ('10', '100', '1000', '10000', '100000'), horizontal=True)
    st.button(
        action + " " + db + '@' + dataset + tp_size + ' on ' + device + (
            ' ' + test + '(' + qCnt + ')' if action == 'test' else ''),
        help="Submit a Jenkins job execution",
        on_click=actionRow,
        args=(device, action, db, dataset, tp_size, test, qCnt)
    )

    st.button(
        action + " History: " + db + '@' + dataset + tp_size + (' ' + test + '(' + qCnt + ')' if action == 'test' else ''),
        on_click=showHistory,
        args=(device, action, db, dataset, tp_size, test, qCnt)
    )
